{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "df706df7",
   "metadata": {},
   "source": [
    "# Ludii Translator\n",
    "- Translate Ludii to GDL: translated Tic-Tac-Toe currently"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "322d6b5f",
   "metadata": {},
   "outputs": [],
   "source": [
    "import re"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a214b906",
   "metadata": {},
   "source": [
    "## Constant"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "e29ac7cd",
   "metadata": {},
   "outputs": [],
   "source": [
    "CELL_MART = ['x', 'o']\n",
    "TERMINAL_CONDITION = ['WIN', 'DRAW', 'LOSS']\n",
    "PLAYERREWARD = {\"WIN\":100, \"DRAW\":50, \"LOSS\":0} "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9d51b184",
   "metadata": {},
   "source": [
    "## Class Translater"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "120a4a9e",
   "metadata": {},
   "outputs": [],
   "source": [
    "class Translator:\n",
    "    def __init__(self, fileName):\n",
    "        self.info = loadLudii(fileName)\n",
    "        self.players = self.extractPlayers()\n",
    "        self.board = self.extractBoard()\n",
    "        self.end = self.extractEnd()\n",
    "        \n",
    "    \n",
    "    \n",
    "    def extractPlayers(self):\n",
    "        \"\"\"\n",
    "        extract players information\n",
    "        \"\"\"\n",
    "        list_pl = []\n",
    "        for var in self.info['equipment']:\n",
    "            gName = re.search(\".*(P\\d*)\", var)\n",
    "            if gName:\n",
    "                list_pl.append(gName.group(1))\n",
    "        return list_pl\n",
    "    \n",
    "    \n",
    "    def extractBoard(self):\n",
    "        \"\"\"\n",
    "        extract board information\n",
    "        \"\"\"\n",
    "        for var in self.info['equipment']:\n",
    "            board = re.search(\"board \\((.*)\\){2}\", var)\n",
    "            if board:\n",
    "                return board.group(1)\n",
    "    \n",
    "    \n",
    "    def extractEnd(self):\n",
    "        list_end = []\n",
    "        for var in self.info['rules']:\n",
    "            if \"(end\" in var:\n",
    "                list_end.append(var)\n",
    "        return list_end\n",
    "    \n",
    "    \n",
    "    def translating(self):\n",
    "        with open(self.info['game']+'.gdl', 'w+') as fp:\n",
    "            \n",
    "            # translating game name\n",
    "            fp.write(translateGame(self.info['game']))\n",
    "            \n",
    "            # translating players\n",
    "            fp.write(translatePlayers(self.players))\n",
    "            \n",
    "            # translating game type\n",
    "            # turn-based game\n",
    "            fp.write(translateMode(self.players))\n",
    "            \n",
    "            # translating board\n",
    "            fp.write(translateBoard(self.board, self.players[0]))\n",
    "            \n",
    "            # translating winCondition\n",
    "            fp.write(translatedWinCondition(self.end, self.board))\n",
    "            \n",
    "            # translating legal action\n",
    "            fp.write(translatedLegalAction(self.players, self.board))\n",
    "            \n",
    "            # translating move & update\n",
    "            fp.write(translatedMoveAndUpdate(self.players))\n",
    "            \n",
    "            \n",
    "            #translating end (reward & terminal)\n",
    "            fp.write(translatedEnd(self.end, self.players))\n",
    "        pass"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c3e964bd",
   "metadata": {},
   "source": [
    "## class BoardConvert\n",
    "- process keyword 'board'\n",
    "- type and size"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "6d22669d",
   "metadata": {},
   "outputs": [],
   "source": [
    "class BoardConvert:\n",
    "    def __init__(self, boardType, boardSize, initPlayer):\n",
    "        self.boardType = boardType\n",
    "        self.boardSize = boardSize\n",
    "        self.initPlayer = initPlayer\n",
    "    \n",
    "    \n",
    "    def convert(self):\n",
    "        context = \";\"*80 + \"\\n\" + \";; Initial State\\n\" + \";\"*80 + \"\\n\\n\"\n",
    "        \n",
    "        # translating square type\n",
    "        if self.boardType == \"square\":\n",
    "            for i in range(1, self.boardSize+1):\n",
    "                for j in range(1, self.boardSize+1):\n",
    "                    context += f\"(init (cell {i} {j} b))\\n\"\n",
    "            context += f\"(init (control {self.initPlayer}))\\n\\n\"\n",
    "        return context"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cd21733d",
   "metadata": {},
   "source": [
    "## Class Terminal\n",
    "- process keywork 'end'\n",
    "- win condition"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "3ccac4ff",
   "metadata": {},
   "outputs": [],
   "source": [
    "class Terminal:    \n",
    "    def __init__(self, endInfor, players, winCon, boardInfo):\n",
    "        self.win_Dict = self.decompositionEnd(endInfor)\n",
    "        self.players = players\n",
    "        self.winCon = winCon\n",
    "        self.boardInfo = boardInfo\n",
    "    \n",
    "    \n",
    "    def decompositionEnd(self, Infor):\n",
    "        if Infor:\n",
    "            end_dict = {}\n",
    "            for var in Infor:\n",
    "                endVar = re.search(\"\\(end \\(if \\((.*)\\) \\((.*)\\)\\)\\)\" ,var)\n",
    "                if endVar:\n",
    "                    end_dict[endVar.group(1)] = endVar.group(2)\n",
    "            return end_dict\n",
    "        else:\n",
    "            return None\n",
    "        \n",
    "        \n",
    "    def convertEndInfo(self):\n",
    "        context = \";\"*80 + \"\\n\" + \";;; Reward\\n\" + \";\"*80 + \"\\n\\n\"\n",
    "        for key, var in self.win_Dict.items():\n",
    "            if \"is Line\" in key and \"result Mover Win\" in var:\n",
    "                # reward\n",
    "                for i in range(len(TERMINAL_CONDITION)):\n",
    "                        for j in range(len(self.players)):\n",
    "                            if PLAYERREWARD[TERMINAL_CONDITION[i]] == 100:\n",
    "                                context += f\"(<= (goal {self.players[j]} {PLAYERREWARD[TERMINAL_CONDITION[i]]}) (line {CELL_MART[j]}))\\n\"\n",
    "                            elif PLAYERREWARD[TERMINAL_CONDITION[i]] == 0:\n",
    "                                context += f\"(<= (goal {self.players[j]} {PLAYERREWARD[TERMINAL_CONDITION[i]]}) (line {CELL_MART[j-1]}))\\n\"\n",
    "                            else:\n",
    "                                context += f\"(<= (goal {self.players[j]} {PLAYERREWARD[TERMINAL_CONDITION[i]]}) \"\n",
    "                                for z in range(len(self.players)):\n",
    "                                    context += f\"(not (line {CELL_MART[z]})) \"c\n",
    "                                context += \"(not open))\\n\"\n",
    "                \n",
    "                \n",
    "                # terminal\n",
    "                context += \"\\n\"+\";\"*80 + \"\\n\" + \";;; End\\n\" + \";\"*80 + \"\\n\\n\"\n",
    "                for i in range(len(TERMINAL_CONDITION)):\n",
    "                    if i < len(self.players):\n",
    "                        context += f\"(<= terminal(line {CELL_MART[i]}))\\n\"\n",
    "                    else:\n",
    "                        context += \"(<= terminal(not open))\\n\\n\" # draw\n",
    "        return context\n",
    "\n",
    "\n",
    "\n",
    "    def convertWinInfo(self, mode=\"Line\"):\n",
    "        if mode == \"Line\" and \"square\" in self.boardInfo:\n",
    "            \n",
    "            # row\n",
    "            contextRow = \"(<= (row ?m ?x)\"\n",
    "            contextCol = \"(<= (column ?n ?x)\"\n",
    "            contextDia1 = \"(<= (diagonal ?x)\"\n",
    "            contextDia2 = \"(<= (diagonal ?x)\"\n",
    "            for i in range(int(self.boardInfo[7])):\n",
    "                contextRow += f\" (true (cell ?m {i+1} ?x))\"\n",
    "                contextCol += f\" (true (cell {i+1} ?n ?x))\"\n",
    "                contextDia1 += f\" (true (cell 1 {i+1} ?x))\"\n",
    "                contextDia2 += f\" (true (cell 1 {int(self.boardInfo[7])-i} ?x))\"\n",
    "            contextRow += \"\\n\"\n",
    "            contextCol += \"\\n\"\n",
    "            contextDia1 += \"\\n\"\n",
    "            contextDia2 += \"\\n\"\n",
    "            \n",
    "            context = contextRow + contextCol + contextDia1 + contextDia2 + \"\\n\"\n",
    "            context += \"(<= (line ?x) (row ?m ?x))\\n(<= (line ?x) (column ?m ?x))\\n(<= (line ?x) (diagonal ?x))\\n\\n\"\n",
    "        return context\n",
    "    \n",
    "    "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3229b4a5",
   "metadata": {},
   "source": [
    "## Class Utils"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "91cfb722",
   "metadata": {},
   "outputs": [],
   "source": [
    "def loadLudii(fileName):\n",
    "    '''\n",
    "    loading Ludii and store the information as dict type\n",
    "    :param fileName: the filename of game\n",
    "    return a dict that contain the information of correspond game\n",
    "    '''\n",
    "    info = \"\".join(readfile(fileName).split(\"//\")[:-1]).split(\"\\n\")\n",
    "    \n",
    "    info_dict = {}\n",
    "    for i in range(len(info)):\n",
    "        if \"game\" in info[i]:\n",
    "            info_dict[\"game\"] = info[i].strip()[7:-1]\n",
    "\n",
    "        elif \"players\" in info[i]:\n",
    "            info_dict[\"players\"] = int(info[i].strip()[9:-1])\n",
    "\n",
    "        elif \"equipment\" in info[i]:\n",
    "            list_eq = []\n",
    "            i += 1\n",
    "            while \"})\" not in info[i]:\n",
    "                list_eq.append(info[i].strip())\n",
    "                i += 1\n",
    "            info_dict[\"equipment\"] = list_eq\n",
    "\n",
    "        elif \"rules\" in info[i]:\n",
    "            list_ru = []\n",
    "            i += 1\n",
    "            while len(info[i].strip()) > 1:\n",
    "                list_ru.append(info[i].strip())\n",
    "                i += 1\n",
    "            info_dict[\"rules\"] = list_ru\n",
    "    return info_dict\n",
    "\n",
    "\n",
    "def readfile(fileName):\n",
    "    '''\n",
    "    read the file\n",
    "    :param fileName: the name of file\n",
    "    return the context of file\n",
    "    '''\n",
    "    with open(fileName) as fp:\n",
    "        return fp.read()\n",
    "\n",
    "\n",
    "def translateGame(gameName):\n",
    "    '''\n",
    "    translate the game name from ludii to GDL\n",
    "    :param gameName: the name of game\n",
    "    return string-based GDL\n",
    "    '''\n",
    "    context = \";\"*80 + \"\\n\" + f\";;; {gameName}\\n\" + \";\"*80 + \"\\n\\n\"\n",
    "    return context\n",
    "\n",
    "\n",
    "def translatePlayers(players):\n",
    "    '''\n",
    "    translate the players description from ludii to GDL\n",
    "    :param players: a list that including the name of player\n",
    "    return string-based GDL\n",
    "    '''\n",
    "    context = \";\"*80 + \"\\n\" + \";; Roles\\n\" + \";\"*80 + \"\\n\\n\"\n",
    "#     for i in range(players):\n",
    "    for var in players:\n",
    "        context += f\"(role {var})\\n\"\n",
    "    context += \"\\n\"\n",
    "    return context\n",
    "\n",
    "\n",
    "def translateMode(players):\n",
    "    \"\"\"\n",
    "    translate the mode\n",
    "    :param players: the list of player\n",
    "    return string-based GDL that including the turn mode\n",
    "    \"\"\"\n",
    "    context = \";\"*80 + \"\\n\" + \";; Game Mode\\n\" + \";\"*80 + \"\\n\\n\"\n",
    "    for i in range(len(players)):\n",
    "        context += f\"(<= (next (control {players[i]})) (true (control {players[(i+1)%len(players)]})))\\n\"\n",
    "    context += \"\\n\"\n",
    "    return context\n",
    "\n",
    "\n",
    "def translateBoard(board, initPlayer):\n",
    "    \"\"\"\n",
    "    translate the board description from ludii to GDL\n",
    "    it contains init each cell and player\n",
    "    :param board: the information of board\n",
    "    :param initPlayer: the player will be controlled first\n",
    "    return string-based GDL that including init cell & players\n",
    "    \"\"\"\n",
    "    bType, bSize = board.split(\" \")\n",
    "    return BoardConvert(bType, int(bSize), initPlayer).convert()\n",
    "\n",
    "\n",
    "def translatedEnd(endInfo, playersInfo):\n",
    "    \"\"\"\n",
    "    translate the end description from ludii to GDL\n",
    "    *keyword 'end' includes reward & terminal in GDL\n",
    "    :param endInfo: end information\n",
    "    :param playersInfo: players Information\n",
    "    return string-based GDL that including reward & terminal\n",
    "    \"\"\"\n",
    "    return Terminal(endInfo, playersInfo, None, None).convertEndInfo()\n",
    "    \n",
    "\n",
    "def translatedWinCondition(winCons, board):\n",
    "    \"\"\"\n",
    "    translate the win-condition(Line) from Ludii to GDL\n",
    "    :param winCons: end information\n",
    "    :param board: board information\n",
    "    \"\"\"\n",
    "    context = \";\"*80 + \"\\n\" + \";; Win Condition\\n\" + \";\"*80 + \"\\n\\n\"\n",
    "    \n",
    "    for winCon in winCons:\n",
    "        if \"is Line\" in winCon:\n",
    "            context += Terminal(None, None, winCon, board).convertWinInfo(mode=\"Line\")\n",
    "    return context\n",
    "\n",
    "\n",
    "def translatedLegalAction(players, board):\n",
    "    \"\"\"\n",
    "      translate the legal action from Ludii to GDL\n",
    "      :param players: players information\n",
    "      :param board: board information\n",
    "      return string-based GDL that including legal-action information\n",
    "    \"\"\"\n",
    "    context = \";\"*80 + \"\\n\" + \";; Legal Action\\n\" + \";\"*80 + \"\\n\\n\"\n",
    "    if \"square\" in board:\n",
    "        for i in range(len(players)):\n",
    "            context += f\"(<= (legal {players[(i+1)%len(players)]} noop) (true (control {players[i]})))\\n\"\n",
    "        context += \"(<= (legal ?w (mark ?x ?y)) (true (cell ?x ?y b)) (true (control ?w)))\\n\\n\"\n",
    "    return context\n",
    "\n",
    "\n",
    "def translatedMoveAndUpdate(players):\n",
    "    \"\"\"\n",
    "        (<= (next (cell ?m ?n x))\n",
    "        (does xplayer (mark ?m ?n))\n",
    "        (true (cell ?m ?n b)))\n",
    "\n",
    "        (<= (next (cell ?m ?n o))\n",
    "        (does oplayer (mark ?m ?n))\n",
    "        (true (cell ?m ?n b)))\n",
    "\n",
    "        (<= (next (cell ?m ?n ?w))\n",
    "        (true (cell ?m ?n ?w))\n",
    "        (distinct ?w b))\n",
    "\n",
    "        (<= (next (cell ?m ?n b))\n",
    "        (does ?w (mark ?j ?k))\n",
    "        (true (cell ?m ?n b))\n",
    "        (or (distinct ?m ?j) (distinct ?n ?k)))\n",
    "    \"\"\"\n",
    "    context = \";\"*80 + \"\\n\" + \";;  Move & Update\\n\" + \";\"*80 + \"\\n\\n\"\n",
    "    for i in range(len(players)):\n",
    "        context += f\"(<= (next (cell ?m ?n {CELL_MART[i]})) (does {players[i]} (mark ?m ?n)) (true (cell ?m ?n b)))\\n\"\n",
    "    \n",
    "    # update mark cell\n",
    "    context += \"(<= (next (cell ?m ?n ?w)) (true (cell ?m ?n ?w)) (distinct ?w b))\\n\"\n",
    "    context += \"(<= (next (cell ?m ?n b)) (does ?w (mark ?j ?k)) (true (cell ?m ?n b)) (or (distinct ?m ?j) (distinct ?n ?k)))\\n\\n\"\n",
    "    return context\n",
    "    \n",
    "    "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ad479f05",
   "metadata": {},
   "source": [
    "# test"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "466632de",
   "metadata": {},
   "source": [
    "## read file"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "ed64d1d8",
   "metadata": {},
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "invalid literal for int() with base 10: '{(player N) (player S)}'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mValueError\u001b[0m                                Traceback (most recent call last)",
      "Input \u001b[0;32mIn [9]\u001b[0m, in \u001b[0;36m<cell line: 1>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0m trl \u001b[38;5;241m=\u001b[39m \u001b[43mTranslator\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mBreakthrough.lud\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n",
      "Input \u001b[0;32mIn [3]\u001b[0m, in \u001b[0;36mTranslator.__init__\u001b[0;34m(self, fileName)\u001b[0m\n\u001b[1;32m      2\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m__init__\u001b[39m(\u001b[38;5;28mself\u001b[39m, fileName):\n\u001b[0;32m----> 3\u001b[0m     \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39minfo \u001b[38;5;241m=\u001b[39m \u001b[43mloadLudii\u001b[49m\u001b[43m(\u001b[49m\u001b[43mfileName\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m      4\u001b[0m     \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mplayers \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mextractPlayers()\n\u001b[1;32m      5\u001b[0m     \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mboard \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mextractBoard()\n",
      "Input \u001b[0;32mIn [6]\u001b[0m, in \u001b[0;36mloadLudii\u001b[0;34m(fileName)\u001b[0m\n\u001b[1;32m     12\u001b[0m     info_dict[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mgame\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m info[i]\u001b[38;5;241m.\u001b[39mstrip()[\u001b[38;5;241m7\u001b[39m:\u001b[38;5;241m-\u001b[39m\u001b[38;5;241m1\u001b[39m]\n\u001b[1;32m     14\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mplayers\u001b[39m\u001b[38;5;124m\"\u001b[39m \u001b[38;5;129;01min\u001b[39;00m info[i]:\n\u001b[0;32m---> 15\u001b[0m     info_dict[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mplayers\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mint\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43minfo\u001b[49m\u001b[43m[\u001b[49m\u001b[43mi\u001b[49m\u001b[43m]\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mstrip\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m9\u001b[39;49m\u001b[43m:\u001b[49m\u001b[38;5;241;43m-\u001b[39;49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m     17\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mequipment\u001b[39m\u001b[38;5;124m\"\u001b[39m \u001b[38;5;129;01min\u001b[39;00m info[i]:\n\u001b[1;32m     18\u001b[0m     list_eq \u001b[38;5;241m=\u001b[39m []\n",
      "\u001b[0;31mValueError\u001b[0m: invalid literal for int() with base 10: '{(player N) (player S)}'"
     ]
    }
   ],
   "source": [
    "trl = Translator('Tic-Tac-Toe.lud')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "82f8b25b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'game': 'Tic-Tac-Toe', 'players': 2, 'equipment': ['(board (square 3))', '(piece \"Disc\" P1)', '(piece \"Cross\" P2)'], 'rules': ['(play (move Add (to (sites Empty))))', '(end (if (is Line 3) (result Mover Win)))']}\n",
      "['P1', 'P2']\n",
      "square 3\n",
      "['(end (if (is Line 3) (result Mover Win)))']\n"
     ]
    }
   ],
   "source": [
    "print(trl.info)\n",
    "print(trl.players)\n",
    "print(trl.board)\n",
    "print(trl.end)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 148,
   "id": "e097173d",
   "metadata": {},
   "outputs": [],
   "source": [
    "trl.translating()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 315,
   "id": "5185572f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n",
      "\n",
      "(<= (goal P1 100) (line x))\n",
      "(<= (goal P2 100) (line o))\n",
      "(<= (goal P1 50) (not (line x)) (not (line o)) (not open))\n",
      "(<= (goal P2 50) (not (line x)) (not (line o)) (not open))\n",
      "(<= (goal P1 0) (line o))\n",
      "(<= (goal P2 0) (line x))\n",
      "\n",
      ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n",
      "\n",
      "(<= terminal(line x))\n",
      "(<= terminal(line o))\n",
      "(<= terminal(not open))\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "print(Terminal(trl.end, trl.players).convert())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 269,
   "id": "cc85ca24",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'is Line 3': 'result Mover Win'}\n"
     ]
    }
   ],
   "source": [
    "print(ee.win_Dict)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d12b46f4",
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "\n",
    "\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
